from django.contrib.auth import get_user_model

from rest_framework import mixins, viewsets, authentication, permissions
from rest_framework.response import Response
from rest_framework.decorators import action

from rest_framework_simplejwt.views import TokenViewBase
from rest_framework_simplejwt.authentication import JWTAuthentication

from .serializers import (BaykeSystemUserSerializer, ChangeEmailSerializer, 
    ChangePasswordSerializer, RegisterSerializer, BaykeSystemMenuSerializer
)
from baykeadmin.common.permissions import IsActiveUser, DjangoModelPermissions
from baykeadmin.config import default
from baykeadmin.apps.system.models import BaykeSystemMenu


User = get_user_model()

class BaykeSystemLoginView(TokenViewBase):
    """ 登录 """
    _serializer_class = default.LOGIN_SERIALIZER


class BaykeUserInfoViewSet(mixins.RetrieveModelMixin, 
                           viewsets.GenericViewSet):
    """ 用户信息 
    该视图仅允许获取当前登录用户的信息
    """
    queryset = User.objects.all()
    serializer_class = BaykeSystemUserSerializer
    authentication_classes = (
        JWTAuthentication, 
        authentication.SessionAuthentication
    )
    permission_classes = (IsActiveUser,)

    def get_queryset(self):
        return super().get_queryset().filter(id=self.request.user.id)

    def get_object(self):
        return self.request.user
    
    def get_serializer_class(self):
        if self.action == 'change_email':
            return ChangeEmailSerializer
        if self.action == 'change_password':
            return ChangePasswordSerializer
        return super().get_serializer_class()
    
    @action(methods=['post'], 
            detail=True, 
            permission_classes=[permissions.IsAuthenticated],
            authentication_classes=(JWTAuthentication,)
        )
    def change_email(self, request, pk=None):
        """ 修改邮箱
        仅允许当前登录用户修改自己的邮箱
        """
        print(request.user)
        instance = self.get_object()
        # 在serializer中验证邮箱是否已存在
        serializer = self.get_serializer(instance, data=request.data)
        serializer.is_valid(raise_exception=True)
        # 走到修改逻辑
        instance.email = serializer.validated_data['email']
        instance.save()
        return Response({'code': 200, 'msg': '修改成功'})
    
    @action(methods=['post'], 
            detail=True, 
            permission_classes=[permissions.IsAuthenticated],
            authentication_classes=(JWTAuthentication,)
        )
    def change_password(self, request, pk=None):
        """ 修改密码
        仅允许当前登录用户修改自己的密码
        """
        instance = self.get_object()
        # 在serializer中验证旧密码正确性
        serializer = self.get_serializer(instance, data=request.data)
        serializer.is_valid(raise_exception=True)
        instance.set_password(serializer.validated_data['password'])
        instance.save()
        # 修改成功了，是否需要考虑清理缓存？ 强制其退出登录？
        # 如果用到了SessionAuthentication，那么需要清理缓存，强制其退出登录
        if authentication.SessionAuthentication in self.authentication_classes:
            from django.contrib.auth import logout
            logout(request)
        return Response({'code': 200, 'msg': '修改成功'})
    

class BaykeSystemRegisterViewSet(mixins.CreateModelMixin, 
                                 viewsets.GenericViewSet):
    """用户注册"""
    queryset = User.objects.all()
    serializer_class = RegisterSerializer


class BaykeSystemMenuViewSet(viewsets.ModelViewSet):
    """菜单管理"""
    queryset = BaykeSystemMenu.objects.all()
    serializer_class = BaykeSystemMenuSerializer
    permission_classes = [DjangoModelPermissions]
    authentication_classes = [
        JWTAuthentication,
        authentication.SessionAuthentication
    ]
    pagination_class = None

    def get_queryset(self):
        # 超级管理员可以查看所有菜单
        if self.request.user.is_superuser and self.action == 'list':
            return self.queryset.filter(parent__isnull=True)
        elif self.request.user.is_superuser and self.action != 'list':
            return self.queryset
        
        # 获取用户所拥有的角色
        groups = self.request.user.groups.all()
        # 详情、修改、删除、删除菜单
        if self.action != 'list':
            return self.queryset.filter(groups__in=groups)

        # 否则只能查看角色绑定的菜单
        return self.queryset.filter(parent__isnull=True).filter(
            groups__in=groups
        )